package com.zkjl.protect_business.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.zkjl.protect_business.common.BaseException;
import com.zkjl.protect_business.common.Status;
import com.zkjl.protect_business.common.UserThreadLocal;
import com.zkjl.protect_business.entity.*;
import com.zkjl.protect_business.repository.AssessmentPoliticalRepository;
import com.zkjl.protect_business.repository.BusinessRepository;
import com.zkjl.protect_business.repository.OrganizationRepository;
import com.zkjl.protect_business.repository.UserRepository;
import com.zkjl.protect_business.service.*;
import com.zkjl.protect_business.utils.DateUtil;
import com.zkjl.protect_business.utils.QueryUtil;
import com.zkjl.protect_business.vo.statistic.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static com.zkjl.protect_business.common.Consts.*;

@Service
@Slf4j
public class StatisticServiceImpl implements StatisticService {

    @Autowired
    BusinessService businessService;
    @Autowired
    BusinessRepository businessRepository;
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    OrganizationService organizationService;
    @Autowired
    DocumentService documentService;
    @Autowired
    UserRepository userRepository;
    @Autowired
    ArchiveService archiveService;

    @Autowired
    OrganizationRepository organizationRepository;
    @Autowired
    AssessmentPoliticalRepository assessmentPoliticalRepository;

    @Override
    public List<EnemySocietyGroupVO> getEnemySocietyStat() {

        Business business = businessRepository.findByName("敌情社情");
        String id = business.getId();

        List<Business> businesses = businessRepository.findAllByPid(id);
        List<EnemySocietyGroupVO> collect2 = businesses.stream().map(business1 -> {
            String id1 = business1.getId();
            String name = business1.getName();
            IndexCoordinates index = businessService.getIndex(id1);

            EnemySocietyGroupVO enemySocietyGroupVO = new EnemySocietyGroupVO();
            enemySocietyGroupVO.setName(name);
            enemySocietyGroupVO.setBusinessId(id1);

            NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder qb = QueryBuilders.boolQuery();
            queryBuilder.withQuery(qb);

            //分页
            Pageable pageable = PageRequest.of(0, 10, Sort.Direction.DESC, "create_time");
            queryBuilder.withPageable(pageable);

            //涉及部队数量
            TermsAggregationBuilder builder = AggregationBuilders.terms("forces").field("附近部队.keyword");
            queryBuilder.addAggregation(builder);
            NativeSearchQuery build = queryBuilder.build();
            build.setMaxResults(0);
            SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, index);

            Aggregations aggregations = search.getAggregations();
            ParsedStringTerms businessTypeName = aggregations.get("forces");
            List<ParsedStringTerms.ParsedBucket> buckets = (List<ParsedStringTerms.ParsedBucket>) businessTypeName.getBuckets();
            //涉及部队数
            List<String> collect = buckets.stream().map(bucket -> {
                String keyAsString = bucket.getKeyAsString();
                return keyAsString;
            }).collect(Collectors.toList());

            //最后更新时间
            List<Long> collect1 = search.stream().map(searchHit -> {
                Map<String, Object> content = (Map<String, Object>) searchHit.getContent();
                Long create_time = (Long) content.get("create_time");
                return create_time;
            }).collect(Collectors.toList());

            int i = CollUtil.isNotEmpty(collect) ? collect.size() : 0;
            enemySocietyGroupVO.setInvolvingNum((long) i);

            //总数
            enemySocietyGroupVO.setNum(search.getTotalHits());
            long l = CollUtil.isNotEmpty(collect1) ? collect1.get(0) : 0;

            enemySocietyGroupVO.setUpdateTime(l);
            return enemySocietyGroupVO;
        }).collect(Collectors.toList());

        return collect2;
    }

    @Override
    public List<BusinessStatVO> getBusinessStat(String orgId, Long startTime, Long endTime) {

        if (StringUtils.isBlank(orgId)) {
            orgId = UserThreadLocal.getOrgId();
        }

        //获取所有自定义的业务(父级id为空，且有字段定义的业务)
        List<Business> list = businessService.list();
        String finalOrgId = orgId;
        List<BusinessStatVO> collect = list.stream().filter(business -> {
            String pid = business.getPid();
            List<BusinessField> fields = business.getFields();
            return StringUtils.isNotBlank(pid) && CollUtil.isNotEmpty(fields);
        }).map(business -> {

            String id = business.getId();
            String name = business.getName();
            BusinessStatVO businessStatVO = new BusinessStatVO();
            businessStatVO.setBusinessId(id);
            businessStatVO.setBusinessName(name);
            businessStatVO.setPbusinessId(business.getPid());
            businessStatVO.setPbusinessName(business.getPname());

            List<GroupVO> orgGroup = documentService.listChildrenGroup(id, finalOrgId, startTime, endTime);

//            List<GroupVO> orgGroup = businessService.getAssociatedOrgGroup(id, startTime, endTime);
            businessStatVO.setGroups(orgGroup);

            return businessStatVO;

        }).collect(Collectors.toList());

        return collect;
    }

    @Override
    public List<BusinessStatVO> getCustomBusinessStat(Long startTime, Long endTime, String orgId) {
        List<BusinessStatVO> result = new ArrayList<>();

        //获取固定业务统计
        //政治考核
        Business assessmentPolitical = businessRepository.findByName(ASSESSMENT_POLITICAL);
        String assessmentPoliticalId = assessmentPolitical.getId();

        BusinessStatVO assessmentPoliticalStat = new BusinessStatVO();
        List<GroupVO> assessmentPoliticalGroup = businessService.getOrgGroup(ASSESSMENT_POLITICAL + "_*", startTime, endTime, orgId);
        assessmentPoliticalStat.setBusinessName(ASSESSMENT_POLITICAL);
        assessmentPoliticalStat.setBusinessId(assessmentPoliticalId);
        assessmentPoliticalStat.setGroups(assessmentPoliticalGroup);
        result.add(assessmentPoliticalStat);


        //政治考核
        Business enemySociety = businessRepository.findByName(ENEMY_SOCIETY);
        String enemySocietyId = enemySociety.getId();

        BusinessStatVO assessmentPoliticalStat1 = new BusinessStatVO();
        List<GroupVO> assessmentPoliticalGroup1 = businessService.getOrgGroup(ENEMY_SOCIETY + "_*", startTime, endTime, orgId);
        assessmentPoliticalStat1.setBusinessName(ENEMY_SOCIETY);
        assessmentPoliticalStat1.setBusinessId(enemySocietyId);
        assessmentPoliticalStat1.setGroups(assessmentPoliticalGroup1);
        result.add(assessmentPoliticalStat1);

        return result;
    }

    @Override
    public List<OrgStatVO> getOrgStat() {

        //所有地区
        List<String> orgRegionGroup = organizationService.getOrgRegionGroup();

        if (CollUtil.isEmpty(orgRegionGroup)) {
            return null;
        }
        List<OrgStatVO> collect = orgRegionGroup.stream().map(region -> {

            OrgStatVO orgStatVO = new OrgStatVO();
            orgStatVO.setRegion(region);
            List<GroupVO> groupVOByRegion = documentService.getGroupVOByRegion(region);
            orgStatVO.setGroups(groupVOByRegion);

            return orgStatVO;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public List<BusinessStatVO> getDateGroup(Long startTime, Long endTime) {


        List<BusinessStatVO> result = new ArrayList<>();

        //获取固定业务统计
        //政治考核
        BusinessStatVO assessmentPoliticalStat = new BusinessStatVO();
        assessmentPoliticalStat.setBusinessName(ASSESSMENT_POLITICAL);
        Business assessmentPolitical = businessRepository.findByName(ASSESSMENT_POLITICAL);
        String assessmentPoliticalId = assessmentPolitical.getId();
        assessmentPoliticalStat.setBusinessId(assessmentPoliticalId);

        List<GroupVO> groupByIndex = documentService.getGroupByIndex(ASSESSMENT_POLITICAL + "_*", startTime, endTime);
        assessmentPoliticalStat.setGroups(groupByIndex);
        result.add(assessmentPoliticalStat);


        //获取所有自定义的业务(父级id为空，且有字段定义的业务)
        List<Business> list = businessService.list();
        List<BusinessStatVO> collect = list.stream().filter(business -> {
            String pid = business.getPid();
            List<BusinessField> fields = business.getFields();
            return StringUtils.isNotBlank(pid) && CollUtil.isNotEmpty(fields);
        }).map(business -> {

            String id = business.getId();
            String name = business.getName();
            BusinessStatVO businessStatVO = new BusinessStatVO();
            businessStatVO.setBusinessId(id);
            businessStatVO.setBusinessName(name);

            List<GroupVO> orgGroup = documentService.getSpecifiedGroupByIndex(id, startTime, endTime);

            businessStatVO.setGroups(orgGroup);

            return businessStatVO;
        }).collect(Collectors.toList());

        result.addAll(collect);

        return result;
    }

    @Override
    public List<OrgStatDateVO> getOrgDateNum(String businessId, Long startTime, Long endTime) {


        Business business = businessService.get(businessId);
        String name = business.getName();
        String pname = business.getPname();

        IndexCoordinates indexCoordinates = QueryUtil.createIndex(name, pname);

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        qb.filter(QueryBuilders.rangeQuery("create_time").gte(startTime));
        qb.filter(QueryBuilders.rangeQuery("create_time").lt(endTime));
        qb.filter(new QueryStringQueryBuilder("true").field("is_doc").defaultOperator(Operator.AND));

        TermsAggregationBuilder builder = AggregationBuilders.terms("orgName").field("create_org_name.keyword");

        //按天分组统计
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram("day").field("create_time")
                .calendarInterval(DateHistogramInterval.DAY)
                .format("yyyy-MM-dd")
                .timeZone(ZoneId.of("Asia/Shanghai"))   //设置时区
                .minDocCount(0);
        dateHistogramAggregationBuilder.subAggregation(builder);

        queryBuilder.withQuery(qb);
        queryBuilder.addAggregation(dateHistogramAggregationBuilder);
        NativeSearchQuery build = queryBuilder.build();
        build.setMaxResults(0);

        SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, indexCoordinates);
        Aggregations aggregations = search.getAggregations();
        if (aggregations == null) {
            return null;
        }

        ParsedDateHistogram day = (ParsedDateHistogram) aggregations.get("day");
        List<ParsedDateHistogram.ParsedBucket> buckets = (List<ParsedDateHistogram.ParsedBucket>) day.getBuckets();
        List<OrgStatDateVO> collect = buckets.stream().map(bucket -> {
            String keyAsString = bucket.getKeyAsString();

            //处理时区
//            DateTime dateTime = DateUtil.date(Long.parseLong(keyAsString));
//            DateTime dateTime1 = DateUtil.offsetHour(dateTime, 8);
//            String dateStr = DateUtil.date(dateTime1).toDateStr();


            Aggregations aggregations1 = bucket.getAggregations();
            List<GroupVO> collect1 = new ArrayList<>();
            if (aggregations1 != null) {
                ParsedStringTerms orgId = aggregations1.get("orgName");

                List<ParsedStringTerms.ParsedBucket> buckets1 = (List<ParsedStringTerms.ParsedBucket>) orgId.getBuckets();

                collect1 = buckets1.stream().map(buckets12 -> {
                    String keyAsString1 = buckets12.getKeyAsString();
//                    Organization organization = organizationService.get(keyAsString1);
                    long docCount = buckets12.getDocCount();
                    GroupVO groupVO = new GroupVO();
                    groupVO.setNum(docCount);
                    groupVO.setKey(keyAsString1);

                    return groupVO;
                }).collect(Collectors.toList());
            }

            OrgStatDateVO orgStatDateVO = new OrgStatDateVO();
            orgStatDateVO.setDate(keyAsString);
            orgStatDateVO.setGroups(collect1);

            return orgStatDateVO;
        }).collect(Collectors.toList());

        return collect;
    }

    @Override
    public StatGroupDTO getFieldNameDate(String orgName, String businessId, Long startTime, Long endTime, String fieldName, String timeType) {

        if (StringUtils.isBlank(orgName)) {
            orgName = UserThreadLocal.getOrg();
        }

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        //判断业务是否指定了发生时间，如果指定了统计就用发生时间统计
        Business business = businessService.get(businessId);
        String occurredTime = business.getOccurredTime();
        String orgFieldName = business.getOrgFieldName();
        if (fieldName.equals(orgFieldName)) {

            StatGroupDTO orgDate = getOrgDate(orgName, businessId, startTime, endTime, fieldName, timeType);
            return orgDate;
        }

        //默认统计时间字段
        String timeFieldName = CREATE_TIME;
        if (StringUtils.isNotBlank(occurredTime)) {
            timeFieldName = occurredTime;
        }

        qb.filter(QueryBuilders.rangeQuery(timeFieldName).gte(startTime));
        qb.filter(QueryBuilders.rangeQuery(timeFieldName).lt(endTime));
        qb.filter(new TermsQueryBuilder(ATTRIBUTION_ORG_NAMES + ".keyword", orgName));

        queryBuilder.withQuery(qb);

        TermsAggregationBuilder builder = AggregationBuilders.terms("fieldName").field(fieldName + ".keyword").minDocCount(0);

        //按天分组统计
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = null;
        if ("day".equals(timeType)) {
            dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram("day").field(timeFieldName)
                    .calendarInterval(DateHistogramInterval.DAY)
                    .format("yyyy-MM-dd")
                    .timeZone(ZoneId.of("Asia/Shanghai"))   //设置时区
                    .minDocCount(0);
        } else if ("month".equals(timeType)) {
            dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram("day").field(timeFieldName)
                    .calendarInterval(DateHistogramInterval.MONTH)
                    .format("yyyy-MM")
                    .timeZone(ZoneId.of("Asia/Shanghai"))   //设置时区
                    .minDocCount(0);
        } else {
            throw new BaseException(Status.DATA_NOT_EXIST.getCode(), "请选择统计纬度，按天或者按月！");
        }

        dateHistogramAggregationBuilder.subAggregation(builder);

        queryBuilder.addAggregation(dateHistogramAggregationBuilder);
        NativeSearchQuery build = queryBuilder.build();
        build.setMaxResults(0);

        IndexCoordinates index = businessService.getIndex(businessId);
        SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, index);
        Aggregations aggregations = search.getAggregations();
        if (aggregations == null) {
            return null;
        }

        //所有key
        List<String> keys = accessToAllFields(orgName, businessId, startTime, endTime, fieldName);

        ParsedDateHistogram day = (ParsedDateHistogram) aggregations.get("day");
        List<ParsedDateHistogram.ParsedBucket> buckets = (List<ParsedDateHistogram.ParsedBucket>) day.getBuckets();
        List<OrgStatDateVO> collect = buckets.stream().map(bucket -> {
            String keyAsString = bucket.getKeyAsString();

            Aggregations aggregations1 = bucket.getAggregations();
            List<GroupVO> collect1 = new ArrayList<>();
            if (aggregations1 != null) {
                ParsedStringTerms fieldNameTerms = aggregations1.get("fieldName");

                List<ParsedStringTerms.ParsedBucket> buckets1 = (List<ParsedStringTerms.ParsedBucket>) fieldNameTerms.getBuckets();

                collect1 = buckets1.stream().map(buckets12 -> {
                    String keyAsString1 = buckets12.getKeyAsString();
                    long docCount = buckets12.getDocCount();
                    GroupVO groupVO = new GroupVO();
                    groupVO.setNum(docCount);
                    groupVO.setKey(keyAsString1);

                    return groupVO;
                }).collect(Collectors.toList());

                //手动补零
                List<String> existing = collect1.stream().map(groupVO -> {
                    String key = groupVO.getKey();
                    return key;
                }).collect(Collectors.toList());

                Collection<String> disjunction = CollUtil.disjunction(existing, keys);
                if (CollUtil.isNotEmpty(disjunction)) {
                    List<GroupVO> collect2 = disjunction.stream().map(key -> {
                        GroupVO groupVO = new GroupVO();
                        groupVO.setKey(key);
                        groupVO.setNum((long) 0);
                        return groupVO;
                    }).collect(Collectors.toList());
                    collect1.addAll(collect2);
                }

            }

            OrgStatDateVO orgStatDateVO = new OrgStatDateVO();
            orgStatDateVO.setDate(keyAsString);
            orgStatDateVO.setGroups(collect1);

            return orgStatDateVO;
        }).collect(Collectors.toList());

        StatGroupDTO statGroupDTO = new StatGroupDTO();
        String jsonStr = JSONUtil.toJsonStr(collect);
        JSONArray jsonArray = JSONUtil.parseArray(jsonStr);
        List<OrgStatDateVO> orgStatDateVOS1 = JSONUtil.toList(jsonArray, OrgStatDateVO.class);
        statGroupDTO.setNormal(orgStatDateVOS1);

        List<OrgStatDateVO> orgStatDateVOS = processingOrder(collect);
        statGroupDTO.setCumulative(orgStatDateVOS);

        return statGroupDTO;
    }


    /**
     * 添加统计的查询条件
     *
     * @param param
     * @param qb
     * @param businessId
     */
    public void addQuery(Map<String, Object> param, BoolQueryBuilder qb, Business business, String timeFieldName) {

        Long startTime = MapUtil.getLong(param, "startTime");
        Long endTime = MapUtil.getLong(param, "endTime");
        qb.filter(QueryBuilders.rangeQuery(timeFieldName).gte(startTime));
        qb.filter(QueryBuilders.rangeQuery(timeFieldName).lt(endTime));

        String org = UserThreadLocal.getOrg();
        qb.filter(new TermsQueryBuilder(ATTRIBUTION_ORG_NAMES + ".keyword", org));

        //全局关键词
        String searchStr = MapUtil.getStr(param, "search");
        if (StringUtils.isNotEmpty(searchStr)) {
            //精确匹配  https://blog.csdn.net/hereiskxm/article/details/47979013
            MultiMatchQueryBuilder type = new MultiMatchQueryBuilder(searchStr).type(MultiMatchQueryBuilder.Type.PHRASE).slop(0);
            qb.filter(type);
        }

        //处理字段类型
        List<BusinessField> fields = business.getFields();
        HashMap<String, Object> map = new HashMap<>();
        fields.stream().forEach(field1 -> {
            String key = field1.getKey();
            String type = field1.getType();
            map.put(key, type);
        });

        if (param != null) {
            Set<Map.Entry<String, Object>> entries = param.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                String key = entry.getKey();
                //排除这几个自定义的字段
                if ("search,sort,order,pageSize,pageNum,archiveId,fieldName,timeType,startTime,endTime".contains(key)) {
                    continue;
                }
                Object value = entry.getValue();
                //时间格式 中间用~分隔
                if ((value + "").contains("~")) {
                    String string = value.toString();
                    String[] split = string.split("~");
                    qb.filter(QueryBuilders.rangeQuery(key).gte(split[0]));
                    qb.filter(QueryBuilders.rangeQuery(key).lte(split[1]));
                } else {

                    String orgFieldName = business.getOrgFieldName();

                    //如果用指定单位字段查询就在特定字段里面取查
                    if (key.equals(orgFieldName)) {

                        BoolQueryBuilder qb2 = QueryBuilders.boolQuery();
                        qb2.should(new TermsQueryBuilder(ATTRIBUTION_ORG_NAMES + ".keyword", value));
                        qb2.should(QueryBuilders.termQuery(key + ".keyword", value));
                        qb.filter(qb2);
                    } else {
                        if ("list".equals(map.get(key))) {
                            qb.filter(QueryBuilders.termQuery(key + ".keyword", value));
                        } else {
                            qb.filter(new QueryStringQueryBuilder("\"" + value + "\"").field(key).defaultOperator(Operator.AND));
                        }
                    }

                }

            }
        }

    }

    @Override
    public StatGroupDTO getFieldNameDate(String businessId, String fieldName, Map<String, Object> param) {


        //判断业务是否指定了发生时间，如果指定了统计就用发生时间统计
        Business business = businessService.get(businessId);
        String occurredTime = business.getOccurredTime();

        //默认统计时间字段
        String timeFieldName = CREATE_TIME;
        if (StringUtils.isNotBlank(occurredTime)) {
            timeFieldName = occurredTime;
        }

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        addQuery(param, qb, business, timeFieldName);

        queryBuilder.withQuery(qb);

        TermsAggregationBuilder builder = AggregationBuilders.terms("fieldName").field(fieldName + ".keyword");

        //按天分组统计
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = null;
        String timeType = MapUtil.getStr(param, "timeType");
        if ("day".equals(timeType)) {
            dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram("day").field(timeFieldName)
                    .calendarInterval(DateHistogramInterval.DAY)
                    .format("yyyy-MM-dd")
                    .timeZone(ZoneId.of("Asia/Shanghai"))   //设置时区
                    .minDocCount(0);
        } else if ("month".equals(timeType)) {
            dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram("day").field(timeFieldName)
                    .calendarInterval(DateHistogramInterval.MONTH)
                    .format("yyyy-MM")
                    .timeZone(ZoneId.of("Asia/Shanghai"))   //设置时区
                    .minDocCount(0);
        } else {
            throw new BaseException(Status.DATA_NOT_EXIST.getCode(), "请选择统计纬度，按天或者按月！");
        }

        dateHistogramAggregationBuilder.subAggregation(builder);

        queryBuilder.addAggregation(dateHistogramAggregationBuilder);
        NativeSearchQuery build = queryBuilder.build();
        build.setMaxResults(0);

        //存档id
        String archiveId = MapUtil.getStr(param, "archiveId");
        IndexCoordinates index = businessService.getIndex(businessId);
        if (StringUtils.isNotBlank(archiveId)) {
            Archive archive = archiveService.get(archiveId);
            String indexName = archive.getIndexName();
            index = IndexCoordinates.of(indexName);
        }

        SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, index);
        Aggregations aggregations = search.getAggregations();
        if (aggregations == null) {
            return null;
        }

        //所有key
        List<String> keys = accessToAllFields(businessId, fieldName, param);

        ParsedDateHistogram day = (ParsedDateHistogram) aggregations.get("day");
        List<ParsedDateHistogram.ParsedBucket> buckets = (List<ParsedDateHistogram.ParsedBucket>) day.getBuckets();
        List<OrgStatDateVO> collect = buckets.stream().map(bucket -> {
            String keyAsString = bucket.getKeyAsString();

            Aggregations aggregations1 = bucket.getAggregations();
            List<GroupVO> collect1 = new ArrayList<>();
            if (aggregations1 != null) {
                ParsedStringTerms fieldNameTerms = aggregations1.get("fieldName");

                List<ParsedStringTerms.ParsedBucket> buckets1 = (List<ParsedStringTerms.ParsedBucket>) fieldNameTerms.getBuckets();

                collect1 = buckets1.stream().map(buckets12 -> {
                    String keyAsString1 = buckets12.getKeyAsString();
                    long docCount = buckets12.getDocCount();
                    GroupVO groupVO = new GroupVO();
                    groupVO.setNum(docCount);
                    groupVO.setKey(keyAsString1);

                    return groupVO;
                }).collect(Collectors.toList());

                //手动补零
                List<String> existing = collect1.stream().map(groupVO -> {
                    String key = groupVO.getKey();
                    return key;
                }).collect(Collectors.toList());

                Collection<String> disjunction = CollUtil.disjunction(existing, keys);
                if (CollUtil.isNotEmpty(disjunction)) {
                    List<GroupVO> collect2 = disjunction.stream().map(key -> {
                        GroupVO groupVO = new GroupVO();
                        groupVO.setKey(key);
                        groupVO.setNum((long) 0);
                        return groupVO;
                    }).collect(Collectors.toList());
                    collect1.addAll(collect2);
                }

            }

            OrgStatDateVO orgStatDateVO = new OrgStatDateVO();
            orgStatDateVO.setDate(keyAsString);
            orgStatDateVO.setGroups(collect1);

            return orgStatDateVO;
        }).collect(Collectors.toList());

        StatGroupDTO statGroupDTO = new StatGroupDTO();
        String jsonStr = JSONUtil.toJsonStr(collect);
        JSONArray jsonArray = JSONUtil.parseArray(jsonStr);
        List<OrgStatDateVO> orgStatDateVOS1 = JSONUtil.toList(jsonArray, OrgStatDateVO.class);
        statGroupDTO.setNormal(orgStatDateVOS1);

        List<OrgStatDateVO> orgStatDateVOS = processingOrder(collect);
        statGroupDTO.setCumulative(orgStatDateVOS);

        return statGroupDTO;
    }


    /**
     * 获取所有字段
     * @param orgName
     * @param businessId
     * @param startTime
     * @param endTime
     * @param fieldName
     * @return
     */
    public List<String> accessToAllFields(String orgName, String businessId, Long startTime, Long endTime, String fieldName) {

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        //判断业务是否指定了发生时间，如果指定了统计就用发生时间统计
        Business business = businessService.get(businessId);
        String occurredTime = business.getOccurredTime();

        //默认统计时间字段
        String timeFieldName = CREATE_TIME;
        if (StringUtils.isNotBlank(occurredTime)) {
            timeFieldName = occurredTime;
        }
        //下防止自动面这个是为了补零失效
        qb.filter(QueryBuilders.rangeQuery(timeFieldName).gte(startTime));
        qb.filter(QueryBuilders.rangeQuery(timeFieldName).lt(endTime));
        qb.filter(new TermsQueryBuilder(ATTRIBUTION_ORG_NAMES + ".keyword", orgName));

        queryBuilder.withQuery(qb);

        TermsAggregationBuilder builder = AggregationBuilders.terms("fieldName").field(fieldName + ".keyword");
        queryBuilder.addAggregation(builder);
        NativeSearchQuery build = queryBuilder.build();
        build.setMaxResults(0);

        IndexCoordinates index = businessService.getIndex(businessId);
        SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, index);
        Aggregations aggregations = search.getAggregations();
        if (aggregations == null) {
            return null;
        }

        ParsedStringTerms day = (ParsedStringTerms) aggregations.get("fieldName");
        List<ParsedStringTerms.ParsedBucket> buckets = (List<ParsedStringTerms.ParsedBucket>) day.getBuckets();
        List<String> collect = buckets.stream().map(bucket -> {
            String keyAsString = bucket.getKeyAsString();
            return keyAsString;
        }).collect(Collectors.toList());

        return collect;

    }


    /**
     * 获取所有字段
     * @return
     */
    public List<String> accessToAllFields(String businessId, String fieldName,Map<String, Object> param) {

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        //判断业务是否指定了发生时间，如果指定了统计就用发生时间统计
        Business business = businessService.get(businessId);
        String occurredTime = business.getOccurredTime();

        //默认统计时间字段
        String timeFieldName = CREATE_TIME;
        if (StringUtils.isNotBlank(occurredTime)) {
            timeFieldName = occurredTime;
        }

        addQuery(param, qb, business, timeFieldName);
        queryBuilder.withQuery(qb);

        TermsAggregationBuilder builder = AggregationBuilders.terms("fieldName").field(fieldName + ".keyword").size(1000);
        queryBuilder.addAggregation(builder);
        NativeSearchQuery build = queryBuilder.build();
        build.setMaxResults(0);

        //存档id
        String archiveId = MapUtil.getStr(param, "archiveId");
        IndexCoordinates index = businessService.getIndex(businessId);
        if (StringUtils.isNotBlank(archiveId)) {
            Archive archive = archiveService.get(archiveId);
            String indexName = archive.getIndexName();
            index = IndexCoordinates.of(indexName);
        }

        SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, index);
        Aggregations aggregations = search.getAggregations();
        if (aggregations == null) {
            return null;
        }

        ParsedStringTerms day = (ParsedStringTerms) aggregations.get("fieldName");
        List<ParsedStringTerms.ParsedBucket> buckets = (List<ParsedStringTerms.ParsedBucket>) day.getBuckets();
        List<String> collect = buckets.stream().map(bucket -> {
            String keyAsString = bucket.getKeyAsString();
            return keyAsString;
        }).collect(Collectors.toList());

        return collect;

    }


    /**
     * 处理顺序
     * @param collect
     * @return
     */
    public List<OrgStatDateVO> processingOrder(List<OrgStatDateVO> collect) {

        List<OrgStatDateVO> clone = ObjectUtil.clone(collect);

        //记录顺序
        List<GroupVO> groups1 = new ArrayList<>();

        //每次数据累积
        Map<String, Long> map = new HashMap<>();
        for (OrgStatDateVO orgStatDateVO : clone) {
            List<GroupVO> groups = orgStatDateVO.getGroups();
            if (CollUtil.isEmpty(groups1)) {
                groups1 = groups;
            }

            if (CollUtil.isEmpty(groups)) {
                groups = new ArrayList<>();
                List<GroupVO> finalGroups = groups;
                map.forEach((key, value) ->{
                    GroupVO groupVO = new GroupVO();
                    groupVO.setKey(key);
                    groupVO.setNum(value);
                    finalGroups.add(groupVO);
                });
                orgStatDateVO.setGroups(finalGroups);
            }else {

                for (GroupVO group : groups) {
                    String key = group.getKey();
                    Long num = group.getNum();
                    Long aLong = map.get(key);

                    if (aLong != null) {
                        long end = num + aLong;
                        group.setNum(end);
                        map.put(key, end);
                    }else {
                        map.put(key, num);
                    }
                }

                List<GroupVO> objects = new ArrayList<>();
                //处理顺序
                for (GroupVO groupVO : groups1) {
                    String key = groupVO.getKey();

                    for (GroupVO group : groups) {
                        String key1 = group.getKey();
                        if (key.equals(key1)) {
                            objects.add(group);
                        }
                    }

                }
                orgStatDateVO.setGroups(objects);
            }
        }

        return clone;
    }

    @Override
    public StatGroupDTO getOrgDate(String orgName, String businessId, Long startTime, Long endTime, String fieldName, String timeType) {

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        Organization org = organizationRepository.findByOrgNameOrOrgNum(orgName, orgName);
        if (org == null) {
            throw new BaseException(Status.DATA_NOT_EXIST.getCode(), "该单位在系统中未找到，无法查看详细数据！");
        }

        //只显示当前下级
        List<Organization> allByPid = organizationRepository.findAllByPid(org.getId());
        List<String> all = allByPid.stream().map(organization -> {
            String orgName1 = organization.getOrgName();
            return orgName1;
        }).collect(Collectors.toList());


        qb.filter(new TermsQueryBuilder(ATTRIBUTION_ORG_NAMES + ".keyword", orgName));

        //判断业务是否指定了发生时间，如果指定了统计就用发生时间统计
        Business business = businessService.get(businessId);
        String occurredTime = business.getOccurredTime();

        //默认统计时间字段
        String timeFieldName = CREATE_TIME;
        if (StringUtils.isNotBlank(occurredTime)) {
            timeFieldName = occurredTime;
        }

        qb.filter(QueryBuilders.rangeQuery(timeFieldName).gte(startTime));
        qb.filter(QueryBuilders.rangeQuery(timeFieldName).lt(endTime));

        queryBuilder.withQuery(qb);

        //必须加size ,凌晨4点的教训，不加size默认值只有10个，数量会缺失
        TermsAggregationBuilder builder = AggregationBuilders.terms("fieldName").field(ATTRIBUTION_ORG_NAMES + ".keyword").minDocCount(0).size(1000);

        //按天分组统计
        DateHistogramAggregationBuilder dateHistogramAggregationBuilder = null;
        if ("day".equals(timeType)) {
            dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram("day").field(timeFieldName)
                    .calendarInterval(DateHistogramInterval.DAY)
                    .format("yyyy-MM-dd")
                    .timeZone(ZoneId.of("Asia/Shanghai"))   //设置时区
                    .minDocCount(0);
        } else if ("month".equals(timeType)) {
            dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram("day").field(timeFieldName)
                    .calendarInterval(DateHistogramInterval.MONTH)
                    .format("yyyy-MM")
                    .timeZone(ZoneId.of("Asia/Shanghai"))   //设置时区
                    .minDocCount(0);
        } else {
            throw new BaseException(Status.DATA_NOT_EXIST.getCode(), "请选择统计纬度，按天或者按月！");
        }

        dateHistogramAggregationBuilder.subAggregation(builder);

        queryBuilder.addAggregation(dateHistogramAggregationBuilder);
        NativeSearchQuery build = queryBuilder.build();
        build.setMaxResults(0);

        IndexCoordinates index = businessService.getIndex(businessId);
        SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, index);
        Aggregations aggregations = search.getAggregations();
        if (aggregations == null) {
            return null;
        }

        ParsedDateHistogram day = (ParsedDateHistogram) aggregations.get("day");
        List<ParsedDateHistogram.ParsedBucket> buckets = (List<ParsedDateHistogram.ParsedBucket>) day.getBuckets();
        List<OrgStatDateVO> collect = buckets.stream().map(bucket -> {
            String keyAsString = bucket.getKeyAsString();

            Aggregations aggregations1 = bucket.getAggregations();
            List<GroupVO> collect1 = new ArrayList<>();
            if (aggregations1 != null) {
                ParsedStringTerms fieldNameTerms = aggregations1.get("fieldName");

                List<ParsedStringTerms.ParsedBucket> buckets1 = (List<ParsedStringTerms.ParsedBucket>) fieldNameTerms.getBuckets();

                collect1 = buckets1.stream().filter(buckets12 ->{
                    String keyAsString1 = buckets12.getKeyAsString();
                    return all.contains(keyAsString1);
                }).map(buckets12 -> {
                    String keyAsString1 = buckets12.getKeyAsString();
                    long docCount = buckets12.getDocCount();
                    GroupVO groupVO = new GroupVO();
                    groupVO.setNum(docCount);
                    groupVO.setKey(keyAsString1);

                    return groupVO;
                }).collect(Collectors.toList());
            }

            //手动补零
            List<String> existing = collect1.stream().map(groupVO -> {
                String key = groupVO.getKey();
                return key;
            }).collect(Collectors.toList());

            Collection<String> disjunction = CollUtil.disjunction(existing, all);
            if (CollUtil.isNotEmpty(disjunction)) {
                List<GroupVO> collect2 = disjunction.stream().map(key -> {
                    GroupVO groupVO = new GroupVO();
                    groupVO.setKey(key);
                    groupVO.setNum((long) 0);
                    return groupVO;
                }).collect(Collectors.toList());
                collect1.addAll(collect2);
            }

            OrgStatDateVO orgStatDateVO = new OrgStatDateVO();
            orgStatDateVO.setDate(keyAsString);
            orgStatDateVO.setGroups(collect1);

            return orgStatDateVO;
        }).collect(Collectors.toList());


        StatGroupDTO statGroupDTO = new StatGroupDTO();
        String jsonStr = JSONUtil.toJsonStr(collect);
        JSONArray jsonArray = JSONUtil.parseArray(jsonStr);
        List<OrgStatDateVO> orgStatDateVOS1 = JSONUtil.toList(jsonArray, OrgStatDateVO.class);
        statGroupDTO.setNormal(orgStatDateVOS1);

        List<OrgStatDateVO> orgStatDateVOS = processingOrder(collect);
        statGroupDTO.setCumulative(orgStatDateVOS);

        return statGroupDTO;
    }

    @Override
    public List<GroupVO> getOrgGroup(String businessId, Long startTime, Long endTime) {

        Business business = businessService.get(businessId);
        String name = business.getName();
        String pname = business.getPname();

        IndexCoordinates indexCoordinates = QueryUtil.createIndex(name, pname);

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        qb.filter(QueryBuilders.rangeQuery("create_time").gte(startTime));
        qb.filter(QueryBuilders.rangeQuery("create_time").lt(endTime));
        qb.filter(new QueryStringQueryBuilder("true").field("is_doc").defaultOperator(Operator.AND));

        TermsAggregationBuilder builder = AggregationBuilders.terms("orgName").field("create_org_name.keyword");

        queryBuilder.withQuery(qb);
        queryBuilder.addAggregation(builder);
        NativeSearchQuery build = queryBuilder.build();
        build.setMaxResults(0);

        SearchHits<Object> search = elasticsearchRestTemplate.search(build, Object.class, indexCoordinates);
        Aggregations aggregations = search.getAggregations();
        if (aggregations == null) {
            return null;
        }

        ParsedStringTerms orgId = aggregations.get("orgName");

        List<ParsedStringTerms.ParsedBucket> buckets1 = (List<ParsedStringTerms.ParsedBucket>) orgId.getBuckets();

        List<GroupVO> collect = buckets1.stream().map(buckets12 -> {
            String keyAsString1 = buckets12.getKeyAsString();
//            Organization organization = organizationService.get(keyAsString1);

            long docCount = buckets12.getDocCount();
            GroupVO groupVO = new GroupVO();
            groupVO.setNum(docCount);
            groupVO.setKey(keyAsString1);

            return groupVO;
        }).collect(Collectors.toList());

        return collect;
    }

    @Override
    public List<GroupVO> getSecondaryGroup(String businessId) {


        List<Business> businesses = businessService.listByPid(businessId);
        if (CollUtil.isNotEmpty(businesses)) {
            return null;
        }

        List<GroupVO> collect = businesses.stream().map(business -> {
            String name = business.getName();
            String id = business.getId();
            Long docNum = businessService.getDocNum(id);
            GroupVO groupVO = new GroupVO();
            groupVO.setKey(name);
            groupVO.setNum(docNum);
            return groupVO;
        }).collect(Collectors.toList());


        return collect;
    }

    @Override
    public List<OrgStatDateVO> getSecondaryDateGroup(String businessId) {

        Business business = businessService.get(businessId);
        String name = business.getName();

        List<OrgStatDateVO> dateGroup = businessService.getDateGroup(name + "_*");


        return dateGroup;
    }

    @Override
    public HomePageCountVO getHomePageCount() {

        HomePageCountVO homePageCountVO = new HomePageCountVO();

        //今日新增文档数量
        long today = DateUtil.getMillis(DateUtil.today());
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder qb = QueryBuilders.boolQuery();
        qb.filter(new QueryStringQueryBuilder("true").field("is_doc").defaultOperator(Operator.AND));
        queryBuilder.withQuery(qb);
        IndexCoordinates indexCoordinates = IndexCoordinates.of(INDEX_PREFIX + "*");

        //文档总数
        long count1 = elasticsearchRestTemplate.count(queryBuilder.build(), indexCoordinates);
        homePageCountVO.setDocNum(count1);

        //业务数量
        List<Business> list = businessService.list();
        int size = list.size();
        homePageCountVO.setBusinessNum((long) size);

        //用户数量
        Iterable<User> all = userRepository.findAll();
        ArrayList<User> users = Lists.newArrayList(all);
        int size1 = users.size();
        homePageCountVO.setUserNum((long) size1);

        //今日新增文档
        qb.filter(QueryBuilders.rangeQuery("create_time").gte(today));
        queryBuilder.withQuery(qb);
        long count = elasticsearchRestTemplate.count(queryBuilder.build(), indexCoordinates);
        homePageCountVO.setTodayDocNum(count);

        return homePageCountVO;
    }
}
